﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Linq;

namespace umbraco.DataServices.Linq
{
    /// <summary>
    /// Lazy Loaded Dynamic Property Collection
    /// </summary>
    public class UmbracoPropertyCollection : IEnumerable<KeyValuePair<string,object>> {

        private readonly Dictionary<string, object> _cache = new Dictionary<string, object>();

        public UmbracoPropertyCollection(UmbracoNode node) {
            if (node == null)
                throw new ArgumentNullException("node");
            UmbracoNode = node;
        }

        public UmbracoNode UmbracoNode { get; private set; }

        public IEnumerator<KeyValuePair<string, object>> GetEnumerator() {
            var property = UmbracoNode.Context.Schema.GetProperties(UmbracoNode.Element);
            return property.Select(item => new KeyValuePair<string, object>(item.Key, LoadProperty(item.Key, item.Value))).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        public object GetValue(string alias) {
            //Attach To Schema Provider
            if (string.IsNullOrEmpty(alias))
                return null;

            //Return If In Cache
            if (_cache.ContainsKey(alias))
                return _cache[alias];

            //Get From XML
            var property = UmbracoNode.Context.Schema.GetProperty(UmbracoNode.Element, alias);
            var propertyValue = LoadProperty(alias, property);
            _cache.Add(alias, propertyValue); //Add To Cache
            return propertyValue;
        }

        private object LoadProperty(string alias, string property) {
            var registeredProperties = UmbracoNode.Context.RegisteredPropertyTypes;
            var propertyId = new PropertyIdentifier(UmbracoNode.DocumentTypeId, alias);
            var targetProperty = typeof(string);
            if (registeredProperties.ContainsKey(propertyId))
                targetProperty = registeredProperties[propertyId];

            if (targetProperty == typeof(string)) {
                if (property == null)
                    return null; //Return Null If Element Doesnt Exist
                if (property == string.Empty || property == "")
                    return ""; //Return Empty String If No Value
                return property;
            }

            if (targetProperty == typeof(int)) {
                if (string.IsNullOrEmpty(property))
                    return default(int); //Doesn't Allow Null - Return default(int)
                return int.Parse(property);
            }

            if (targetProperty == typeof(DateTime)) {
                if (string.IsNullOrEmpty(property))
                    return default(DateTime); //Doesn't Allow Null - Return default(DateTime)
                return DateTime.Parse(property);
            }

            throw new NotSupportedException(targetProperty.Name + "  Is Not A Supported Property Type");
        }
    }
}
